/*
  Copyright (C) 2011, Kyungjoo Kim
  
  This file is part of LINAL (LINear ALgebra)
  
  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
  
  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  Also add information on how to contact you by electronic and paper mail.
  
  
  Kyungjoo Kim
  iamkyungjoo@gmail.com
*/
#ifndef LINAL_UTIL_STREAM_HXX
#define LINAL_UTIL_STREAM_HXX

namespace linal {

  template<class T_> 
  std::ostream& operator<<(std::ostream &os, const std::auto_ptr<T_> &p) {
    return os;
  }

  // IO stream
  std::istream& read_to_endl(std::istream& in, std::string& str);
  std::istream& move_to_endl(std::istream& in);
  std::istream& skip_comment(std::istream& in);

  // Clasic IO
  bool read_line(FILE *fp, Char_ **line_out);
  bool open_file(Char_ *fullpath, Char_ *mode, FILE **fp);
  bool close_file(FILE *fp);
  bool disp(FILE *fp, Char_ *format, ...);
  
  class Disp_ {
    friend std::ostream& operator<<(std::ostream& os, const Disp_& disp);
  private:
  protected:
  public:
    Disp_() { }
    virtual ~Disp_() { }
    virtual std::ostream& content(std::ostream& os) const {
      return (os << "[LINAL] ");
    }
  };
}

/*! Implementation
 */
inline std::istream& linal::read_to_endl(std::istream& in, 
                                         std::string& str) {
  Char_ c;
  while ( in.get(c) && c != '\n')
    str += c;
  return in;
}
inline std::istream& linal::move_to_endl(std::istream& in) {
  Char_ c;
  while ( in.get(c) && c != '\n')
    ;
  return in;
}
inline std::istream& linal::skip_comment(std::istream& in) {
  Char_ c;
  while( (in >> c) && c == '#')
    in >> move_to_endl;
  in.putback(c);
  return in;
}

inline bool linal::read_line(FILE *fp, Char_ **line_out) {
  Char_ line_in[10000];
  Char_ *c;

  while (fgets(line_in, 1000, fp) != NULL) {
    c = line_in;
    while (*c && *c <= ' ') c++;

    // skip the comment line                                                            
    if (*c && *c != '#') {
      *line_out = line_in;
      return true;
    }
  }
  *line_out = NULL;
  return false;
}

inline bool linal::open_file(Char_ *fullpath, Char_ *mode, FILE **fp) {
  *fp = fopen(fullpath, mode);
  if (*fp == NULL) {
    fprintf(stderr, "[LINAL] fail to open file : %s\n", fullpath);
    return false;
  }
  return true;
}

inline bool linal::close_file(FILE *fp) {
  if (fclose(fp)) {
    fprintf(stderr,"[LINAL] fail to close file");
    return false;
  }
  return true;
}

inline bool linal::disp(FILE *fp, Char_ *format, ...) {
  Char_ buffer[2048];
  va_list args;
  va_start( args, format );
  vsprintf( buffer, format, args );
  fprintf ( fp, "%s", buffer );
  va_end( args );

  return true;
}

#endif
